package event;

import java.util.HashMap;
import java.util.Vector;
import main.EventCallbackFunctionOwner;
import main.EventCallbackFunctionOwner.OutgoingComplexEventInfo;

public class EventCallbackManager {

	private static EventCallbackManager sInstance = null;

	public static EventCallbackManager instance() {
		if (sInstance == null)
			sInstance = new EventCallbackManager();

		return sInstance;
	}

	// streamID -> callback functions
	private HashMap<Long, Vector<DEFINES.CEPLEventCallback>> callbacks = null;

	// streamID -> callback functions for vector of events
	private HashMap<Long, Vector<DEFINES.CEPLEventCallback>> vectorCallbacks = null;

	private EventCallbackManager() {
		init();
	}

	public void reset() {
		if (callbacks != null)
			callbacks.clear();
		if (vectorCallbacks != null)
			vectorCallbacks.clear();
	}

	protected void finalize() {
		reset();
	}

	public void init() {
		reset();
		callbacks = new HashMap<Long, Vector<DEFINES.CEPLEventCallback>>();
		vectorCallbacks = new HashMap<Long, Vector<DEFINES.CEPLEventCallback>>();
	}

	public void addEventCallback(long streamID,
			EventCallbackFunctionOwner object) {
		DEFINES.CEPLEventCallback callback = new DEFINES.CEPLEventCallback(
				object, true);
		if (callbacks.get(new Long(streamID)) == null)
			callbacks.put(new Long(streamID),
					new Vector<DEFINES.CEPLEventCallback>());
		callbacks.get(new Long(streamID)).add(callback);
	}

	public void activateEventCallback(long streamID,
			EventCallbackFunctionOwner object) {
		Vector<DEFINES.CEPLEventCallback> temp = callbacks.get(new Long(
				streamID));
		if (temp != null) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).functionOwner.equals(object))
					temp.get(i).active = true;
			}
		}
	}

	public void deactivateEventCallback(long streamID,
			EventCallbackFunctionOwner object) {
		Vector<DEFINES.CEPLEventCallback> temp = callbacks.get(new Long(
				streamID));
		if (temp != null) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).functionOwner.equals(object))
					temp.get(i).active = false;
			}
		}
	}

	public void removeEventCallback(long streamID,
			EventCallbackFunctionOwner object) {
		Vector<DEFINES.CEPLEventCallback> temp = callbacks.get(new Long(
				streamID));
		if (temp != null) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).functionOwner.equals(object)) {
					temp.remove(i);
					--i;
				}
			}
		}
	}

	// same functions as above, but for callback-functions that will be
	// called for a set of new complex events, caused by the same
	// pushed event
	public void addEventVectorCallback(long streamID,
			EventCallbackFunctionOwner object) {
		DEFINES.CEPLEventCallback callback = new DEFINES.CEPLEventCallback(
				object, true);
		if (vectorCallbacks.get(new Long(streamID)) == null)
			vectorCallbacks.put(new Long(streamID),
					new Vector<DEFINES.CEPLEventCallback>());
		vectorCallbacks.get(new Long(streamID)).add(callback);
	}

	public void activateEventVectorCallback(long streamID,
			EventCallbackFunctionOwner object) {
		Vector<DEFINES.CEPLEventCallback> temp = vectorCallbacks.get(new Long(
				streamID));
		if (temp != null) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).functionOwner.equals(object))
					temp.get(i).active = true;
			}
		}
	}

	public void deactivateEventVectorCallback(long streamID,
			EventCallbackFunctionOwner object) {
		Vector<DEFINES.CEPLEventCallback> temp = vectorCallbacks.get(new Long(
				streamID));
		if (temp != null) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).functionOwner.equals(object))
					temp.get(i).active = false;
			}
		}
	}

	public void removeEventVectorCallback(long streamID,
			EventCallbackFunctionOwner object) {
		Vector<DEFINES.CEPLEventCallback> temp = vectorCallbacks.get(new Long(
				streamID));
		if (temp != null) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).functionOwner.equals(object)) {
					temp.remove(i);
					--i;
				}
			}
		}
	}

	public void fireEvent(Event e) {
		OutgoingComplexEventInfo ocei = new OutgoingComplexEventInfo();
		ocei.streamID = e.getStreamID();
		ocei.eventID = e.getID();
		ocei.timestamp = e.getTimestamp();
		ocei.eventData = e.getEventData().clone();

		Vector<DEFINES.CEPLEventCallback> temp = callbacks.get(new Long(
				ocei.streamID));
		if (temp != null) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).active)
					temp.get(i).functionOwner
							.callFunctionForNewComplexEvent(ocei);
			}
		}
	}

	public void fireVectorOfEvents(Vector<Event> vectorOfEvents) {
		Vector<OutgoingComplexEventInfo> converted = new Vector<OutgoingComplexEventInfo>();
		long streamID = -1;

		for (int i = 0; i < vectorOfEvents.size(); ++i) {
			Event e = vectorOfEvents.get(i);
			OutgoingComplexEventInfo ocei = new OutgoingComplexEventInfo();
			ocei.streamID = e.getStreamID();
			ocei.eventID = e.getID();
			ocei.timestamp = e.getTimestamp();
			ocei.eventData = e.getEventData().clone();

			streamID = ocei.streamID;
			converted.add(ocei);
		}

		Vector<DEFINES.CEPLEventCallback> temp = vectorCallbacks.get(new Long(
				streamID));
		if (temp != null && streamID != -1) {
			for (int i = 0; i < temp.size(); ++i) {
				if (temp.get(i).active)
					temp.get(i).functionOwner
							.callFunctionForVectorOfNewComplexEvents(converted);
			}
		}
	}

	public boolean isEventCallbackAvailable(long streamID) {
		Vector<DEFINES.CEPLEventCallback> temp = callbacks.get(new Long(
				streamID));

		return (temp != null && temp.size() > 0);
	}

	public boolean isEventVectorCallbackAvailable(long streamID) {
		Vector<DEFINES.CEPLEventCallback> temp2 = vectorCallbacks.get(new Long(
				streamID));

		return (temp2 != null && temp2.size() > 0);
	}
}
